using System;
using System.Drawing;
using System.IO;
using Clandestine.Base;
using Lime;

namespace Clandestine.Graphics
{
	public partial class Sprite : Renderable, IHasTransform2D
	{
		public RenderList RenderList { get; private set; }
		public Graphics Graphics { get; private set; }

		public Transform2D Transform { get; set; }

		public bool IgnoreCameraTint = true;
		public bool FlipHorizontal = false;
		public bool Superbright = false;

		public Color4 Color = Color4.White;

		internal virtual Texture Texture { get; set; }

		#region Texture property wrapping

		public virtual string GetBitmapFilename()
		{
			return Texture.Identifier;
		}

		public virtual Size UnscaledSize
		{
			get { return Texture.Size; }
		}

		#endregion

		// For stuff that inherits us and the like.
		internal Sprite(Graphics g) : this(g.DefaultRenderList) { }
		internal Sprite(RenderList list)
			: base(list.Graphics, list)
		{
			this.Graphics = list.Graphics;
			this.RenderList = list;
			this.Transform = new Transform2D();
		}

		// Note that Textures.Add(), when presented with a null bitmap, tries to load automatically using the identifier as a filename.
		public Sprite(Graphics g, string filename) : this(g.DefaultRenderList, filename, null) { }
		public Sprite(Graphics g, Bitmap bitmap) : this(g.DefaultRenderList, (System.Guid.NewGuid().ToString()), bitmap) { }
		public Sprite(Graphics g, string identifier, Bitmap bitmap) : this(g.DefaultRenderList, identifier, bitmap) { }
		public Sprite(RenderList list, string filename) : this(list, filename, new Bitmap(filename)) { }
		public Sprite(RenderList list, Bitmap bitmap) : this(list, (System.Guid.NewGuid().ToString()), bitmap) { }
		public Sprite(RenderList list, string identifier, Bitmap bitmap) 
			: this (list)		
		{
			// is bitmap null? they might be trying to pass in a texture identifier, not a filename
			// -- not really advised! better passing in a Texture obj these days for that if the identifier isn't a filename itself
			if (bitmap == null)
			{
				// try set Texture to an existing one with identifier as name
				this.Texture = Graphics.Textures.Get(identifier);
				if (this.Texture == null)
					this.Texture = Graphics.Textures.AddBitmap(identifier, new Bitmap(identifier));
				return;
			}
			
			this.Texture = Graphics.Textures.AddBitmap(identifier, bitmap); // Keep this last in constructor - this is how .Render() checks whether we're ready or not!
		}

		public Sprite(RenderList list, Texture texture) : this(list)
		{
			this.Texture = texture; // todo: reference counts through Textures.cs; don't want to touch ReferenceCount outside there, as it gets messy.
		}
		
		public override void Dispose()
		{
			if (this.Texture != null)
				this.Texture.Dispose(); 
			base.Dispose();
		}
		
		protected override void render()
		{
			if (this.Texture == null || this.Texture.ReferenceCount == 0) // not ready?
				return;

			this.Transform.BeginTransformed();

			int width = UnscaledSize.Width;
			int height = UnscaledSize.Height;

			GL.Enable(EnableCap.Texture2D);

			GL.BindTexture(TextureTarget.Texture2D, Texture.TexturePointer);
			
			if (!IgnoreCameraTint)
			{
				Color4 c = Color.Multiply(Graphics.Camera.Tint);
				GL.Color4(c.R, c.G, c.B, c.A);
			}
			else
				GL.Color4(Color.R, Color.G, Color.B, Color.A);

			if (!Superbright)
				GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
			else
				GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One);

			// remember chaps, culling order is clockwise.
			GL.Begin(BeginMode.Quads);
			if (!FlipHorizontal)
			{
				// DRAWING NORMALLY!
				// Top-left!
				GL.TexCoord2(Texture.TopLeftTexCoord[0], Texture.TopLeftTexCoord[1]);
				GL.Vertex3(0, 0, 0f);
				// Top-right!
				GL.TexCoord2(Texture.BottomRightTexCoord[0], Texture.TopLeftTexCoord[1]);
				GL.Vertex3(width, 0, 0f);
				// Bottom-right!
				GL.TexCoord2(Texture.BottomRightTexCoord[0], Texture.BottomRightTexCoord[1]);
				GL.Vertex3(width, height, 0f);
				// Bottom-left!
				GL.TexCoord2(Texture.TopLeftTexCoord[0], Texture.BottomRightTexCoord[1]);
				GL.Vertex3(0, height, 0f);
			}
			else
			{
				// FLIPPING HORIZONTALLY!
				// Top-left!
				GL.TexCoord2(Texture.BottomRightTexCoord[0], Texture.TopLeftTexCoord[1]);
				GL.Vertex3(0, 0, 0f);
				// Top-right!
				GL.TexCoord2(Texture.TopLeftTexCoord[0], Texture.TopLeftTexCoord[1]);
				GL.Vertex3(width, 0, 0f);
				// Bottom-right!
				GL.TexCoord2(Texture.TopLeftTexCoord[0], Texture.BottomRightTexCoord[1]);
				GL.Vertex3(width, height, 0f);
				// Bottom-left!
				GL.TexCoord2(Texture.BottomRightTexCoord[0], Texture.BottomRightTexCoord[1]);
				GL.Vertex3(0, height, 0f);
			}
			// Aaah, done.
			GL.End();

			GL.Disable(EnableCap.Texture2D);

			this.Transform.EndTransformed();
		}
	}
}

